package com.lin.manager.secure.access;

import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.vote.AbstractAccessDecisionManager;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;
import java.util.List;

/**
 * @作者: 林江
 * @创建时间: 2024/3/17
 * @功能: 自定义访问角色控制器
 */
public class CustomAccessDecisionManager extends AbstractAccessDecisionManager {

    protected CustomAccessDecisionManager(List<AccessDecisionVoter<?>> decisionVoters) {
        super(decisionVoters);
    }

    /**
     * 投票
     *
     * @param authentication   已经认证的用户
     * @param object           FilterInvocation对象，可以获取当前请求对象
     * @param configAttributes FilterInvocationSecurityMetadataSource 中的 getAttributes() 方法的返回值，即当前请求URL所需的角色
     *                         权限[角色,菜单,表达式]
     */
    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        // 获取当前登录用户的角色信息
        Collection<? extends GrantedAuthority> auths = authentication.getAuthorities();

        // 遍历当前请求 URL 所需要的角色信息（这里角色以 |admin|user| 形式放回所以只判断一次）
        for (ConfigAttribute configAttribute : configAttributes) {
            if ("ROLE_ANONYMOUS".equals(configAttribute.getAttribute())) {
                return;
            }

            // 遍历当前登录用户的角色信息，判断是否具备当前请求 URL 所需要的角色信息
            for (GrantedAuthority authority : auths) {
                if (configAttribute.getAttribute().contains("|" + authority.getAuthority() + "|")) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("拒绝访问 - 未授权");
    }

}
